package org.zero;

import java.lang.instrument.Instrumentation;

/**
 * premain 和 agentmain 都是 Java 虚拟机（JVM）为了支持 Java Agent 技术而提供的两种不同的入口点。
 * 它们允许开发者在 JVM 启动阶段或者运行时动态地插入代码以监控、修改或增强应用的行为。
 *
 * @author zero
 * @since 2021/1/11
 */
public class AgentBootstrap {
    /**
     * premain 是预加载机制，适用于在应用启动之初就需要对类加载过程进行干预的情况。
     * <p>
     * premain 是在应用程序 main 方法执行前由 JVM 调用的方法。
     * 通过在启动 Java 应用时指定 -javaagent 参数，可以指定包含代理类（agent class）的 jar 包。
     * 在 premain 方法内部，开发者可以执行初始化操作，比如注册一个 ClassFileTransformer 来转换即将被加载的类的字节码。
     * 因为 premain 在类加载之前就运行，所以它非常适合用来实现类级别的操作，比如字节码增强（Bytecode Instrumentation）以实现实时监控、性能分析、AOP（面向切面编程）等功能。
     */
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("是否支持类定义: " + inst.isRedefineClassesSupported());
        System.out.println("是否支持类转换: " + inst.isRetransformClassesSupported());

        inst.addTransformer(new CustomClassFileTransformer(),true);
    }

    /**
     * 不存在{@link AgentBootstrap#premain(String, Instrumentation)}时加载该方法
     */
    public static void premain(String agentArgs) {
    }

    /**
     * agentmain 是后加载机制，适合于在应用运行时动态接入并执行一些运维、调试或修复操作，不适用于修改已经加载的类的字节码。
     * <p>
     * agentmain 方法则是用于 JVM 运行时动态附加（attach）代理的一种方式。
     * 当 JVM 已经启动后，可以通过 Attach API 将 Java Agent 动态地连接到正在运行的 JVM 上。
     * agentmain 方法会在代理成功附加上去之后调用，这意味着它可以用于在运行时修改或注入行为，但此时部分或全部类可能已经被加载完成。
     * 使用场景包括但不限于后期的诊断、监控、故障修复等，由于不能影响已经加载的类，它的功能范围相比于 premain 可能会受到一定限制。
     */
    public static void agentmain(String agentArgs, Instrumentation inst) {

    }

    /**
     * 不存在{@link AgentBootstrap#agentmain(String, Instrumentation)}时加载该方法
     */
    public static void agentmain(String agentArgs) {

    }
}
